#pragma once
#include <iostream>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <utility>
#include <string>
#include <functional>

#include <strings.h>

#include "Log.hpp"

const static std::string base_sep = "\r\n";
const static std::string line_sep = ": ";
const static std::string pre_fix_path = "wwwroot";  // 前缀路径，也就是web根目录路径，wwwroot文件夹所在路径
const static std::string home_page = "index.html";  // 首页
const static std::string http_version = "HTTP/1.0"; // 服务器端HTTP的版本
const static std::string space_sep = " ";
const static std::string html_404 = "wwwroot/404.html";

class HttpRequest
{
public:
    HttpRequest()
        : _blank_line(base_sep), _path(pre_fix_path)
    {
    }

private:
    std::string GetLine(std::string &reqStr)
    {
        int pos = reqStr.find(base_sep);
        if (pos == std::string::npos)
        {
            return "";
        }
        std::string lineStr = reqStr.substr(0, pos);
        reqStr.erase(0, lineStr.size() + base_sep.size());
        return lineStr.empty() ? base_sep : lineStr;
    }
    void ParseReqLine()
    {
        std::stringstream ss(_req_line);   // stringstream将字符串转换成对应的流
        ss >> _method >> _uri >> _version; // 就可以和cin>>使用一样，以空格为分割符一次输入
        // 首先处理GET /login?username=zhangsan&passwd=123456
        if (strcasecmp(_method.c_str(), "GET") == 0)
        {
            // 找到?将uri中的参数提取出来放到_body_txt中统一和POST一样，方便后序处理
            int pos1 = _uri.find("?");
            if (pos1 != std::string::npos)
            {
                _body_txt = _uri.substr(pos1 + 1);
                _uri.resize(pos1);
            }
        }
        // 将uri:/a/b/c转换成./wwwroot/a/b/c
        _path += _uri;
        // 如果rui只有一个/，表示请访问首页资源
        if (_uri == "/")
        {
            _path += home_page;
        }
        int pos = _path.rfind(".");
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }
    void ParseReqHeaders()
    {
        for (std::string &str : _req_headers)
        {
            int pos = str.find(line_sep);
            // 没找到说明这行属性有问题
            if (pos == std::string::npos)
            {
                continue;
            }
            std::string key = str.substr(0, pos);
            std::string value = str.substr(pos + line_sep.size());
            // 如果key、value有空的说明这行属性也有问题
            if (key.empty() || value.empty())
            {
                continue;
            }
            _headers.insert({key, value});
        }
    }

public:
    void Deserialize(std::string &reqStr)
    {
        // 基本的反序列化
        _req_line = GetLine(reqStr);
        std::string line;
        do
        {
            line = GetLine(reqStr);
            if (line.empty() || line == base_sep)
            {
                break;
            }
            _req_headers.push_back(line);
        } while (true);
        if (!reqStr.empty())
        {
            _body_txt = reqStr;
        }
        // 进一步反序列化
        ParseReqLine();    // 解析_req_line
        ParseReqHeaders(); // 解析_req_headers
    }
    std::string Uri()
    {
        return _uri;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        LOG(INFO, "client request suffix is %s\n", _suffix.c_str());
        return _suffix;
    }
    std::string Method()
    {
        LOG(INFO, "client request methode is %s\n", _method.c_str());
        return _method;
    }
    std::string GetBodyText()
    {
        return _body_txt;
    }

    void Print()
    {
        std::cout << "----------------------------" << std::endl;
        std::cout << _req_line << std::endl;
        for (auto &header : _req_headers)
        {
            std::cout << header << std::endl;
        }
        std::cout << _blank_line;
        std::cout << _body_txt << std::endl;
    }

    ~HttpRequest()
    {
    }

private:
    // 基本的HttpRequest格式
    std::string _req_line;                 // 请求行
    std::vector<std::string> _req_headers; // 请求报头
    std::string _blank_line;               // 空行
    std::string _body_txt;                 // 正文部分

    // 需要更具体的字段，需要进一步的反序列化
    std::string _method;                                   // 请求方法
    std::string _uri;                                      // uri
    std::string _path;                                     // 资源在机器上更加完整的路径，将web更目录/更换为./wwwroot
    std::string _suffix;                                   // 资源类型，文件名后缀
    std::string _version;                                  // HTTP版本
    std::unordered_map<std::string, std::string> _headers; // 请求报头中的key和value
};

class HttpResponse
{
public:
    HttpResponse()
        : _http_version(http_version), _blank_line(base_sep)
    {
    }
    // 添加响应属性
    void AddVersion(const std::string &version)
    {
        _http_version = version;
    }
    // 添加状态码
    void AddStateCode(int code, const std::string &des)
    {
        _state_code = code;
        _des = des;
    }
    // 添加报头属性
    void AddHeader(const std::string &key, const std::string &value)
    {
        _heads[key] = value;
    }
    // 添加正文
    void AddBodyText(const std::string &body_text)
    {
        _body_text = body_text;
    }
    // 序列化
    std::string Serialize()
    {
        // 构建状态行
        _status_line = _http_version + space_sep + std::to_string(_state_code) + space_sep + _des + base_sep;
        // 构建响应报头
        for (auto &head : _heads)
        {
            std::string headLine = head.first + line_sep + head.second + base_sep;
            _res_headers.push_back(headLine);
        }

        std::string reqStr = _status_line;
        for (std::string &str : _res_headers)
        {
            reqStr += str;
        }
        reqStr += _blank_line;
        reqStr += _body_text;

        return reqStr;
    }
    ~HttpResponse()
    {
    }

private:
    // HttpRequest属性
    std::string _http_version; // 服务端http的版本
    int _state_code;           // 状态码
    std::string _des;          // 状态码描述
    std::unordered_map<std::string, std::string> _heads;

    // 基本的HttpRequest格式
    std::string _status_line;              // 状态行
    std::vector<std::string> _res_headers; // 响应报头
    std::string _blank_line;               // 空行
    std::string _body_text;                // 正文部分
};

using conduct_t = std::function<HttpResponse(HttpRequest &)>;
class HttpSever
{
private:
    std::string GetFileConnect(const std::string &path)
    {
        // 像图片音频这样的资源是二进制的，只能以二进制形式来读取
        std::ifstream in((const char *)path.c_str(), std::ios::binary);
        if (!in.is_open())
        {
            return "";
        }
        // 判断文件的大小
        in.seekg(0, in.end);       // 更改读写位置为到文件最后
        int fileSize = in.tellg(); // 计算文件大小，当前位置的偏移量
        in.seekg(0, in.beg);       // 更改读写位置为到文件开始，开始读取

        std::string connect;
        connect.resize(fileSize);
        in.read((char *)connect.c_str(), fileSize);

        in.close();
        return connect;
    }

public:
    HttpSever()
    {
        _type_table.insert({".html", "text/html"});
        _type_table.insert({".txt", "text/xml"});
        _type_table.insert({".gif", "image/jpeg"});
        _type_table.insert({".default", "text/html"}); // 如果没有后缀，说明资源不存在，返回数据类型为网页，提示没有该资源的页面

        _code_to_des.insert({200, "OK"});
        _code_to_des.insert({404, "Not Found"});
        _code_to_des.insert({302, "Found"});
    }
    std::string ExecuteHttpSever(std::string &reqStr)
    {
        // 将请求字符串反序列化，拿到资源路径
        HttpRequest request;
        request.Deserialize(reqStr);
        std::string path = request.Path();

        // 构建应答
        HttpResponse response;
        if (request.GetBodyText() != "") // 请求报文正文不为空说明传递过来参数，进行相应的方法处理
        {
            if (_conduct_list.count(path))
            {
                conduct_t func = _conduct_list[request.Path()];
                response = func(request);
            }
        }
        else if (request.Path() == "wwwroot/redir") //<a href="/redir">测试重定向</a>
        {
            response.AddVersion(http_version);
            //"www.qq.com"浏览器还是会向当前这个服务器请求资源
            response.AddHeader("Location", "https://www.qq.com"); // content.html
            response.AddStateCode(302, _code_to_des[302]);
        }
        else // 是请求资源
        {
            // 读取资源内容
            std::string connect = GetFileConnect(path);
            if (connect.empty())
            {
                response.AddVersion(http_version);
                response.AddStateCode(404, _code_to_des[404]);
                connect = GetFileConnect(html_404);
                int bodySize = connect.size();
                response.AddHeader("Content-Length", std::to_string(bodySize));
                response.AddHeader("Content-Type", _type_table[".html"]);
                response.AddBodyText(connect);
            }
            else
            {
                response.AddVersion(http_version);
                response.AddStateCode(200, _code_to_des[200]);
                // 添加响应报头中的字段
                int bodySize = connect.size(); // 如果资源读取成功了，一定要填一个Connect-Length的属性，正文长度
                response.AddHeader("Content-Length", std::to_string(bodySize));
                response.AddHeader("Content-Type", _type_table[request.Suffix()]);
                response.AddHeader("Set-Cookie", "username=zhangsan");
                response.AddHeader("Set-Cookie", "password=123456");
                response.AddBodyText(connect);
            }
        }
        // 序列化
        return response.Serialize();
    }
    void InsertConduct(const std::string conductName, conduct_t func)
    {
        std::string s = pre_fix_path;
        s += conductName;
        _conduct_list[s] = func;
    }

    ~HttpSever()
    {
    }

private:
    std::unordered_map<std::string, std::string> _type_table;
    std::unordered_map<int, std::string> _code_to_des;
    std::unordered_map<std::string, conduct_t> _conduct_list;
};